#include <iostream>
#include <SFML/Graphics.hpp>
#include <tinyxml.h>
#include "../../include/Engine.hpp"
#include "../../include/GUI/WindowBase.hpp"

using namespace std;

namespace GUI
{
    // Fonction créant les bouts d'images pour former la fenêtre
    void WindowBase::initialize_rects()
    {
        m_rects.clear(); // On efface le vector pour être sur qu'il soit bien vide

        //---Barre de titre---

            //Gauche
            m_rects.push_back(sf::IntRect(0,0,m_padding,m_hauteur_titre)); // #0
            //Milieu
            m_rects.push_back(sf::IntRect(m_padding,0,m_base_width-2*m_padding,m_hauteur_titre)); // #1
            //Droite
            m_rects.push_back(sf::IntRect(m_base_width-m_padding,0,m_padding,m_hauteur_titre)); // #2

        //---Corps de la fenêtre---

            //Coin haut gauche
            m_rects.push_back(sf::IntRect(0,m_hauteur_titre,m_padding,m_padding)); // #3
            //Haut
            m_rects.push_back(sf::IntRect(m_padding,m_hauteur_titre,m_base_width-2*m_padding,m_padding)); // #4
            //Coin haut droit
            m_rects.push_back(sf::IntRect(m_base_width-m_padding,m_hauteur_titre,m_padding,m_padding)); // #5
            //Gauche milieu
            m_rects.push_back(sf::IntRect(0,m_hauteur_titre+m_padding,m_padding,m_base_height-m_hauteur_titre-2*m_padding)); // #6
            //Milieu
            m_rects.push_back(sf::IntRect(m_padding,m_hauteur_titre+m_padding,m_base_width-2*m_padding,m_base_height-m_hauteur_titre-2*m_padding)); // #7
            //Droite milieu
            m_rects.push_back(sf::IntRect(m_base_width-m_padding,m_hauteur_titre+m_padding,m_padding,m_base_height-m_hauteur_titre-2*m_padding)); // #8
            //Coin bas gauche
            m_rects.push_back(sf::IntRect(0,m_base_height-m_padding,m_padding,m_padding)); // #9
            //Bas
            m_rects.push_back(sf::IntRect(m_padding,m_base_height-m_padding,m_base_width-2*m_padding,m_padding)); // #10
            //Coin bas droite
            m_rects.push_back(sf::IntRect(m_base_width-m_padding,m_base_height-m_padding,m_padding,m_padding)); // #11
    }
    // Fonction qui charge les données dans GUI.config pour les affectés aux variables
    void WindowBase::initialize_GUI()
    {
        m_hauteur_titre = m_Moteur.Config()->GetGUI()->hauteur_titre;
        m_base_width = m_Moteur.Config()->GetGUI()->base_width;
        m_base_height = m_Moteur.Config()->GetGUI()->base_height;

        m_font_titre = m_Moteur.Config()->GetGUI()->font_titre;
        m_fontsize_titre = m_Moteur.Config()->GetGUI()->titre_size;
        m_font_contenu = m_Moteur.Config()->GetGUI()->font_contenu;
        m_fontsize_contenu = m_Moteur.Config()->GetGUI()->contenu_size;

        m_color_titre = m_Moteur.Config()->GetGUI()->color_titre;
        m_color_contenu = m_Moteur.Config()->GetGUI()->color_contenu;
    }

    // Constructeur
    WindowBase::WindowBase(Engine &Moteur, const sf::String &text) : Widget(Moteur), m_bouton_ouverture(GUI::OpenButton(Moteur)), m_bouton_fermeture(GUI::CloseButton(Moteur))
    {
        initialize_GUI();
        initialize_rects();

        m_sprite.SetImage(*m_Moteur.Graphic()->GetGUIImage(1));
        m_dimensions.width = 250;
        m_dimensions.height = 200;

        m_titre = sf::Text(text, m_font_titre, m_fontsize_titre);
        m_titre.SetColor(m_color_titre);

        m_clicked = false;
        m_espaces.width = 0;
        m_espaces.height = 0;

        m_open = false;
        m_reduite = false;

        m_bouton_ouverture.SetConteneurPosition(m_dimensions.width-16-m_padding, -m_hauteur_titre);
        m_bouton_fermeture.SetConteneurPosition(m_dimensions.width-m_padding, -m_hauteur_titre);

        SetWidget(&m_bouton_ouverture);
        SetWidget(&m_bouton_fermeture);
    }

    void WindowBase::ActualizeWidgetsPosition()
    {
        // Position des objets
        int x = 0;
        int y = 0;
        // On actualise leurs positions
        for(int i=0;i<m_widgets.size();i++)
        {
            x = m_position.x+m_widgets[i]->GetConteneurPosition().x+m_padding;
            y = m_position.y+m_widgets[i]->GetConteneurPosition().y+m_hauteur_titre+m_padding;
            m_widgets[i]->SetPosition(x, y);
        }
    }

    void WindowBase::SetPosition(const int x, const int y)
    {
        m_position.x = x;
        m_position.y = y;

        ActualizeWidgetsPosition();
    }
    void WindowBase::SetPositionX(const int x)
    {
        m_position.x = x;

        ActualizeWidgetsPosition();
    }
    void WindowBase::SetPositionY(const int y)
    {
        m_position.y = y;

        ActualizeWidgetsPosition();
    }
    void WindowBase::SetDimensions(const unsigned int width, const unsigned int height)
    {
        m_dimensions.width = width;
        m_dimensions.height = height;

        // On actualise la position des boutons d'ouverture et de fermeture
        m_bouton_ouverture.SetConteneurPosition(m_dimensions.width-16-m_padding, -m_hauteur_titre);
        m_bouton_fermeture.SetConteneurPosition(m_dimensions.width-m_padding, -m_hauteur_titre);
    }

    void WindowBase::Adjust()
    {
        // Hauteur et largeur de l'objet actuellement analyser
        int width = 0;
        int height = 0;
        // Hauteur et largeur maximal que la fenêtre prendra grâce aux widgets
        int max_width = 0;
        int max_height = 0;

        // On commence à partir de 2 pour éviter les boutons d'ouverture et de fermeture
        for(int i=2;i<m_widgets.size();i++)
        {
            width = m_widgets[i]->GetConteneurPosition().x + m_widgets[i]->GetDimensions().width;
            height = m_widgets[i]->GetConteneurPosition().y + m_widgets[i]->GetDimensions().height;
            if(width > max_width)
                max_width = width;
            if(height > max_height)
                max_height = height;
        }

        if(m_dimensions.width < max_width)
            m_dimensions.width = max_width;
        else
            m_dimensions.width = max_width+2*m_padding;

        if(m_dimensions.height < max_height)
            m_dimensions.height = max_height+2*m_padding;
        else
            m_dimensions.height = max_height;

        // On actualise la position des boutons d'ouverture et de fermeture
        m_bouton_ouverture.SetConteneurPosition(m_dimensions.width-16-m_padding, -m_hauteur_titre);
        m_bouton_fermeture.SetConteneurPosition(m_dimensions.width-m_padding, -m_hauteur_titre);
        ActualizeWidgetsPosition();
    }

    void WindowBase::SetWidget(Widget *widget)
    {
        // On envoie à l'objet sa position réelle à l'écran
        int x = 0;
        int y = 0;

        x = m_position.x+widget->GetConteneurPosition().x+m_padding;
        y = m_position.y+widget->GetConteneurPosition().y+m_hauteur_titre+m_padding;

        m_widgets.push_back(widget);
        m_widgets.back()->SetParent(this);
        m_widgets.back()->SetPosition(x, y);
    }

    bool WindowBase::IsHover()
    {
        int x = m_Moteur.App().GetInput().GetMouseX();
        int y = m_Moteur.App().GetInput().GetMouseY();

        if(!m_reduite)
        {
            if(x >= m_position.x and y >= m_position.y and x <= m_position.x+m_dimensions.width+2*m_padding and y <= m_position.y+m_dimensions.height+2*m_padding+m_hauteur_titre)
                return true;
            else
                return false;
        }
        else // La fenêtre est réduite
        {
            if(x >= m_position.x and y >= m_position.y and x <= m_position.x+m_dimensions.width+2*m_padding and y <= m_position.y+m_hauteur_titre)
                return true;
            else
                return false;
        }
    }

    void WindowBase::UpdateEvent()
    {
        if(m_open)
        {
            int x = m_Moteur.App().GetInput().GetMouseX();
            int y = m_Moteur.App().GetInput().GetMouseY();

            if(!m_reduite)
            {
                for(int i=0;i<m_widgets.size();i++)
                    m_widgets[i]->UpdateEvent();
            }
            else
            {
                for(int i=0;i<2;i++)            // On actualise les boutons de réduction et de fermeture
                    m_widgets[i]->UpdateEvent();
            }

            if(m_Moteur.Event()->Type == sf::Event::MouseButtonPressed)
            {
                if(IsHover())
                {
                    m_clicked = true;
                }
                else
                {
                    m_clicked = false;
                }
            }
            else
            {
                m_clicked = false;
            }

            if(m_clicked and m_Moteur.App().GetInput().IsMouseButtonDown(sf::Mouse::Left))
            {
                //if(IsHover())
                if( x >= m_position.x and x <= (m_position.x+m_dimensions.width-28+m_padding) and y >= m_position.y and y <= (m_position.y+m_hauteur_titre))
                {
                    m_espaces.width = m_Moteur.App().GetInput().GetMouseX()-m_position.x;
                    m_espaces.height = m_Moteur.App().GetInput().GetMouseY()-m_position.y;
                    m_deplacement = true;
                }
            }
            if(m_deplacement and m_Moteur.App().GetInput().IsMouseButtonDown(sf::Mouse::Left))
            {
                if(x > 0 and x < m_Moteur.App().GetWidth())
                {
                    m_position.x = m_Moteur.App().GetInput().GetMouseX()-m_espaces.width;
                }
                if(y > 0 and y < m_Moteur.App().GetHeight())
                {
                    m_position.y = m_Moteur.App().GetInput().GetMouseY()-m_espaces.height;
                }
                ActualizeWidgetsPosition();
            }
            if(m_deplacement and m_Moteur.Event()->Type == sf::Event::MouseButtonReleased)
            {
                m_deplacement = false;
                m_espaces.width = 0;
                m_espaces.height = 0;
            }

            if(m_bouton_fermeture.IsClicked())
            {
                //On ferme la fenêtre
                Close();
            }
            else if(m_bouton_ouverture.IsClicked())
            {
                //On modifie la réduction de la fenêtre
                if(m_reduite)
                    m_reduite = false;
                else
                    m_reduite = true;
            }
        }
    }
    void WindowBase::Afficher()
    {
        if(m_open)
        {
        //--- Barre de titre ---
            m_sprite.SetSubRect(m_rects[0]);
            m_sprite.SetPosition(m_position.x, m_position.y);
            m_sprite.SetScale(1,1);
            m_Moteur.Graphic()->Draw(m_sprite);

            m_sprite.SetSubRect(m_rects[1]);
            m_sprite.SetPosition(m_position.x+m_padding, m_position.y);
            m_sprite.SetScale(m_dimensions.width/(90-2*m_padding),1);
            m_Moteur.Graphic()->Draw(m_sprite);

            m_sprite.SetSubRect(m_rects[2]);
            m_sprite.SetPosition(m_position.x+m_padding+m_dimensions.width, m_position.y);
            m_sprite.SetScale(1,1);
            m_Moteur.Graphic()->Draw(m_sprite);

            m_titre.SetPosition((int)(m_position.x+m_padding+(m_dimensions.width-m_titre.GetRect().Width)/2), (int)(m_position.y-2+(m_hauteur_titre-m_titre.GetRect().Height)/2));
            m_Moteur.Graphic()->Draw(m_titre);

        //Contenu de la fenêtre
            if(!m_reduite)
            {
                m_sprite.SetSubRect(m_rects[3]);
                m_sprite.SetPosition(m_position.x, m_position.y+m_hauteur_titre);
                m_sprite.SetScale(1,1);
                m_Moteur.Graphic()->Draw(m_sprite);

                m_sprite.SetSubRect(m_rects[4]);
                m_sprite.SetPosition(m_position.x+m_padding, m_position.y+m_hauteur_titre);
                m_sprite.SetScale(m_dimensions.width/(90-2*m_padding),1);
                m_Moteur.Graphic()->Draw(m_sprite);

                m_sprite.SetSubRect(m_rects[5]);
                m_sprite.SetPosition(m_position.x+m_padding+m_dimensions.width, m_position.y+m_hauteur_titre);
                m_sprite.SetScale(1,1);
                m_Moteur.Graphic()->Draw(m_sprite);

                m_sprite.SetSubRect(m_rects[6]);
                m_sprite.SetPosition(m_position.x, m_position.y+m_hauteur_titre+m_padding);
                m_sprite.SetScale(1,m_dimensions.height/(90-m_hauteur_titre-2*m_padding));
                m_Moteur.Graphic()->Draw(m_sprite);

                m_sprite.SetSubRect(m_rects[7]);
                m_sprite.SetPosition(m_position.x+m_padding, m_position.y+m_hauteur_titre+m_padding);
                m_sprite.SetScale(m_dimensions.width/(90-2*m_padding),m_dimensions.height/(90-m_hauteur_titre-2*m_padding));
                m_Moteur.Graphic()->Draw(m_sprite);

                m_sprite.SetSubRect(m_rects[8]);
                m_sprite.SetPosition(m_position.x+m_padding+m_dimensions.width, m_position.y+m_hauteur_titre+m_padding);
                m_sprite.SetScale(1,m_dimensions.height/(90-m_hauteur_titre-2*m_padding));
                m_Moteur.Graphic()->Draw(m_sprite);

                m_sprite.SetSubRect(m_rects[9]);
                m_sprite.SetPosition(m_position.x, m_position.y+m_hauteur_titre+m_padding+m_dimensions.height);
                m_sprite.SetScale(1,1);
                m_Moteur.Graphic()->Draw(m_sprite);

                m_sprite.SetSubRect(m_rects[10]);
                m_sprite.SetPosition(m_position.x+m_padding, m_position.y+m_hauteur_titre+m_padding+m_dimensions.height);
                m_sprite.SetScale(m_dimensions.width/(90-2*m_padding),1);
                m_Moteur.Graphic()->Draw(m_sprite);

                m_sprite.SetSubRect(m_rects[11]);
                m_sprite.SetPosition(m_position.x+m_padding+m_dimensions.width, m_position.y+m_hauteur_titre+m_padding+m_dimensions.height);
                m_sprite.SetScale(1,1);
                m_Moteur.Graphic()->Draw(m_sprite);

                for(int i=0;i<m_widgets.size();i++)
                    m_widgets[i]->Afficher();
            }
            else
            {
                for(int i=0;i<2;i++)
                    m_widgets[i]->Afficher();
            }
        }
    }
}
